package cn.remex.db.rsql.aspect;

import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Judgment;
import cn.remex.db.DbCvo;
import cn.remex.db.DbRvo;
import cn.remex.db.exception.RsqlDataException;
import cn.remex.db.exception.RsqlExecuteException;
import cn.remex.db.rsql.RsqlConstants;
import cn.remex.db.rsql.model.Modelable;
import cn.remex.db.sql.Select;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import static cn.remex.core.util.Judgment.nullOrBlank;

@Aspect
public class RsqlMonitorAspect {

	private static boolean isDebug = RsqlConstants.logger.isDebugEnabled();

	@Around("execution(java.util.*List cn.remex.db.model.*.get*())"
			+ "|| execution(java.util.*Map cn.remex.db.model.*.get*())"
			+ "|| execution(java.util.*Set cn.remex.db.model.*.get*())"
			+ "|| execution(java.util.*Vector cn.remex.db.model.*.get*())")
	public Object doAround(final ProceedingJoinPoint pjp) throws Throwable {
		Object retVal = pjp.proceed();
		return retVal;
	}


	@Around("execution(public * cn.remex.db.rsql.RsqlExecutor.execute*(..))")
	public Object doAroundRemexSqlExecute(final ProceedingJoinPoint pjp) throws Throwable {
		long time = System.currentTimeMillis();
		String sqlExecuteMethod = pjp.getSignature().getName();
		DbRvo retVal = null;
		@SuppressWarnings("unchecked")
		DbCvo<?,?> dbCvo = (DbCvo<?,?>) pjp.getArgs()[0];

		String msg = "RsqlExecutor.{}() executed [ {}ms ], Message:\r\n\tSQL: {}\r\n\tParameters: {}\r\n\tDataBase Msg: {}";
		String sql = dbCvo._getSqlString() + (dbCvo._getSqlString().trim().startsWith("SELECT") ? Select.obtainSQLOrder(dbCvo) : "");
		String param = dbCvo._getNamedParams().toString();
		String errorMsg = null;
		try {
			retVal = (DbRvo) pjp.proceed();
		} catch (RsqlExecuteException e) {
			errorMsg = nullOrBlank(e.getMessage())?e.toString():e.getMessage();
			if (null != e.getCause() && e.getCause().getMessage().contains("Duplicate entry")) {
				String causeMsg = e.getCause().getMessage();
				throw new RsqlDataException(ServiceCode.RSQL_DATA_INVALID, "表["+(nullOrBlank(dbCvo.getBeanName())?"-":dbCvo.getBeanName())+"]主键数据重复：" + causeMsg.substring(causeMsg.indexOf("Duplicate entry") + 15, causeMsg.indexOf("for")));
			} else if (null != e.getCause() && e.getCause().getMessage().contains("Data truncation: Data too long")) {
				String causeMsg = e.getCause().getMessage();
				throw new RsqlDataException(ServiceCode.RSQL_DATA_INVALID, "表["+(nullOrBlank(dbCvo.getBeanName())?"-":dbCvo.getBeanName())+"]字段数据过长：" + causeMsg.substring(causeMsg.indexOf("Data too long for column") + 24, causeMsg.indexOf(" at")));
			} else if (null != e.getCause() && e.getCause().getMessage().contains("cannot be null")) {
				String causeMsg = e.getCause().getMessage();
				throw new RsqlDataException(ServiceCode.RSQL_DATA_INVALID, "表["+(nullOrBlank(dbCvo.getBeanName())?"-":dbCvo.getBeanName())+"]字段不能为空：" + causeMsg.substring(causeMsg.indexOf("Column '")+8, causeMsg.indexOf("' cannot be null")));
			} else {
				throw e;
			}
		} catch (Exception e) {
			errorMsg = nullOrBlank(e.getMessage())?e.toString():e.getMessage();
			throw e;
		} finally {
			RsqlConstants.logger.info(msg, sqlExecuteMethod, System.currentTimeMillis() - time, sql, param, retVal!=null?retVal.getMsg():"Rsql操作异常:"+errorMsg);
		}

		return retVal;
	}

}
